package app.bigdata;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.collections.MultiMap;

public class BigDataMain{

	private static ArrayList<StarData> starData;
	private static StringBuffer sbtext;
	private static boolean flag = false;
	
	private static ArrayList<StarData> centroid;

	public static void main(String args[]) {

		File file = new File("C:\\workspace\\BigDataJava\\bigdata\\bsc5.dat");

		StringBuffer sb = new StringBuffer();
		starData = new ArrayList<StarData>();
		centroid = new ArrayList<StarData>();
		
		sbtext = new StringBuffer();

		try{
			BufferedReader br = new BufferedReader(new FileReader(file));
			String line;

			while ((line = br.readLine()) != null) {

				try {
					sb.append(line.substring(0, 4));			// order
					sb.append("   ");
					sb.append(line.substring(11, 14));
					sb.append("   ");
					sb.append(line.substring(90, 96));			// longitude
					sb.append("   ");
					sb.append(line.substring(96, 102));			// latitude
					sb.append("   ");
					sb.append(line.substring(102, 107));		// visual mag
					sb.append("\n");

					starData.add(new StarData(line.substring(0,4) ,line.substring(11, 14)
							,Float.valueOf(line.substring(90, 96)).floatValue()
							,Float.valueOf(line.substring(96, 102)).floatValue()
							,Float.valueOf(line.substring(102, 107)).floatValue()));
				} catch (Exception e) {
					System.out.println("Exception : "+e+" line : "+line.substring(0,4));

				}
			}
		}catch(Exception e){

		}
		
		//System.out.println(sb.toString());

		initCentroid();
		
		for(int i = 0 ; i < Constants.PERFORM_NUM ; i++){
			try{
				startCalc();
				System.out.println("Calculating ...");
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		//System.out.println(sbtext);
		
		flag = true;
		try{
			startCalc();
		}catch(Exception e){

		}
		
	}

	private static void initCentroid(){
		if(!Constants.MANY_CENTROID){
			/*
			centroid.add(new StarData("c1", 90.00f, 45.00f, 1.00f));
			centroid.add(new StarData("c2", 270.00f, 45.00f, 1.00f));
			centroid.add(new StarData("c3", 180.00f, 0.00f, 1.00f));
			centroid.add(new StarData("c4", 90.00f, -45.00f, 1.00f));
			centroid.add(new StarData("c5", 270.00f, -45.00f, 1.00f));
			*/
		}else{
			int count = 0;
			for(int lon = 0 ; lon < 360 ; lon = lon+45){
				for(int lat = -80 ; lat < 90 ; lat = lat+16){
					count++;
					centroid.add(new StarData
							("c"+Integer.toString(count),"centroid"+Integer.toString(count)
									, (float)lon, (float)lat, 1.00f ));
				}
			}

		}
	}
	
	private static void startCalc() throws Exception{
		int num = 0;
		if(Constants.TEST){
			num = Constants.LIMIT;
		}else{
			num = starData.size();
		}

		int centroidLength = centroid.size();
		int[] sumOfLong = new int[centroidLength];
		int[] sumOfLat = new int[centroidLength];
		int[] avgLong = new int[centroidLength];
		int[] avgLat = new int[centroidLength];
		//int[] count = new int[centroidLength];
		int[] deltaLong = new int[centroidLength];
		int[] deltaLat = new int[centroidLength];
		ArrayList<StarData>[] recordAVG = new ArrayList[centroidLength];
		for(int i = 0 ; i < centroidLength ; i++){
			recordAVG[i] = new ArrayList<StarData>();
			avgLong[i] = 0;
			avgLat[i] = 0;
			//count[i] = 0;
			sumOfLat[i] = 0;
			sumOfLong[i] = 0;
			deltaLat[i] = 0;
			deltaLong[i] = 0;
		}
		
		int[] whatIs = new int[num];
		for(int i = 0 ; i < num ; i++){
			whatIs[i] = getDistance(i);
			recordAVG[whatIs[i]].add(new StarData(starData.get(i).getOrder(), 
					 starData.get(i).getStarName()
					,starData.get(i).getLongitude()
					,starData.get(i).getLatitude(), starData.get(i).getMagnitude()));
			sumOfLong[whatIs[i]] += (int)starData.get(i).getLongitude(); 
			sumOfLat[whatIs[i]] += (int)starData.get(i).getLatitude();
			//count[whatIs[i]]++;
		}
		
		for(int i = 0 ; i < centroidLength ; i++){
			GetAVG getAVG = new GetAVG(recordAVG[i]);
			avgLong[i] = (int)getAVG.getAVGLongitude();
			avgLat[i] = (int)getAVG.getAVGLatitude();
		}
		
		for(int i = 0 ; i < centroidLength ; i++){
			try{
				deltaLong[i] = Math.abs((int)centroid.get(i).getLongitude() - avgLong[i]);
				deltaLat[i] = Math.abs((int)centroid.get(i).getLatitude() - avgLat[i]);
				centroid.get(i).setLongitude((float)avgLong[i]);
				centroid.get(i).setLatitude((float)avgLat[i]);
				sbtext.append("["+(i+1)+"] :  longitude :  "+avgLong[i]+" , latitude : "+avgLat[i]+
						"  // deltaLong : "+deltaLong[i]+" , deltaLat : "+deltaLat[i]+"\n");
			}catch(Exception e){
				System.out.println("**** Exception : "+e);
			}
		}

		sbtext.append("\n");

		// Process at last
		if(flag){
			ArrayList<String>[] starStr = new ArrayList[centroidLength];
			for(int i = 0 ; i < centroidLength ; i++){
				starStr[i] = new ArrayList<String>();
				System.out.println("<<centroid"+i+">>");
				
				System.out.println("longitude :  "+avgLong[i]+" , latitude : "+avgLat[i]);
				
				for(int j = 0 ; j < recordAVG[i].size() ; j++){
					if(!"   ".equals(recordAVG[i].get(j).getStarName())){
						System.out.print(recordAVG[i].get(j).getStarName()+",");
						starStr[i].add(recordAVG[i].get(j).getStarName());
					}
				}
				
				System.out.println("\n");
				
				RecordStatistics rs = new RecordStatistics(starStr[i]);
				
				System.out.println("\n");
			}
			
			GetStarMap(starStr);
		}
		
	}
	
	private static void GetStarMap(ArrayList<String>[] starStr) {
		MultiMap mhm = new MultiHashMap();
		
		int starMapLength = starStr.length;	
		for(int i = 0 ; i < starMapLength ; i++){
			for(int j = 0 ; j < starStr[i].size() ; j++){
				mhm.put(starStr[i].get(j), "c"+Integer.toString(i+1));
				
				
			}
		}
		
		System.out.println("multi map size : "+mhm.size());
		/*
		Collection col = mhm.values();
		for(Object value : col){
			System.out.println("value : "+value);
		}*/
		ArrayList<String>[] tempStr = new ArrayList[mhm.size()];
		for(int i = 0 ; i < mhm.size() ; i++){
			tempStr[i] = new ArrayList<String>();
		}
		
		List list = null;
		Set set = mhm.entrySet();
		Iterator i = set.iterator();
		int count = 0;
		while(i.hasNext()) {
			Map.Entry me = (Map.Entry)i.next();
			list=(List)mhm.get(me.getKey());
			System.out.println("\n\n<<"+me.getKey()+">>");
			for(int j=0;j<list.size();j++){
				System.out.print(list.get(j)+",");
				tempStr[count].add((String)list.get(j));
			}
			System.out.println("\n");
			RecordStatistics rs = new RecordStatistics(tempStr[count]);
			count++;
		}	
		
	}

	private static int getDistance(int order) throws Exception{
		int near = -1;
		int centroidLength = centroid.size();
		double[] tempDist = new double[centroidLength];
		double[] sortDist = new double[centroidLength];
		for(int i = 0 ; i < centroidLength ; i++){
			sortDist[i] = Utils.fineDistance(starData.get(order).getLongitude() , centroid.get(i).getLongitude()
					,starData.get(order).getLatitude(), centroid.get(i).getLatitude());
		}
		for(int i = 0 ; i < centroidLength ; i++){
			tempDist[i] = sortDist[i];
		}
		Arrays.sort(sortDist);
		for(int i = 0 ; i < centroidLength ; i++){
			if(sortDist[0] == tempDist[i]){
				near = i;
				break;
			}
		}
		return near;
	}

	Comparator<StarData> comp = new Comparator<StarData>() {
		private final Collator collator = Collator.getInstance();
		public int compare(StarData object1, StarData object2) {
			int flag = 0;
			if(Constants.SORT_TYPE == 0){
				if(object1.getMagnitude() < object2.getMagnitude()){
					flag = -1;
				}else if(object1.getMagnitude() == object2.getMagnitude()){
					flag = 0;
				}else if(object1.getMagnitude() > object2.getMagnitude()){
					flag = 1;
				}
			}else if(Constants.SORT_TYPE == 1){
				if(object1.getLongitude() < object2.getLongitude()){
					flag = -1;
				}else if(object1.getLongitude() == object2.getLongitude() ){
					flag = 0;
				}else if(object1.getLongitude() > object2.getLongitude()){
					flag = 1;
				}
			}else if(Constants.SORT_TYPE == 2){
				if(object1.getLatitude() < object2.getLatitude()){
					flag = -1;
				}else if(object1.getLatitude() == object2.getLatitude()){
					flag = 0;
				}else if(object1.getLatitude() > object2.getLatitude()){
					flag = 1;
				}
			}
			return flag;
		}
	};

}